// ##########################################################################
// #                                                                        #
// #                              CLOUDCOMPARE                              #
// #                                                                        #
// #  This program is free software; you can redistribute it and/or modify  #
// #  it under the terms of the GNU General Public License as published by  #
// #  the Free Software Foundation; version 2 or later of the License.      #
// #                                                                        #
// #  This program is distributed in the hope that it will be useful,       #
// #  but WITHOUT ANY WARRANTY; without even the implied warranty of        #
// #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the          #
// #  GNU General Public License for more details.                          #
// #                                                                        #
// #          COPYRIGHT: EDF R&D / TELECOM ParisTech (ENST-TSI)             #
// #                                                                        #
// ##########################################################################

#ifndef CC_ITEM_DELEGATE_HEADER
#define CC_ITEM_DELEGATE_HEADER

// qCC_db
#include <ccArray.h>
#include <ccPointCloud.h>

// Qt
#include <QStyledItemDelegate>

class cc2DLabel;
class cc2DViewportObject;
class ccCameraSensor;
class ccFacet;
class ccGBLSensor;
class ccGenericMesh;
class ccGenericPointCloud;
class ccGenericPrimitive;
class ccHObject;
class ccImage;
class ccIndexedTransformationBuffer;
class ccKdTree;
class ccMaterialSet;
class ccOctree;
class ccPlanarEntityInterface;
class ccPolyline;
class ccSensor;
class CCShareable;
class ccShiftedObject;
class ccCoordinateSystem;

class QAbstractItemView;
class QStandardItem;
class QStandardItemModel;

//! GUI properties list dialog element
class ccPropertiesTreeDelegate : public QStyledItemDelegate
{
	Q_OBJECT

  public:
	//! Delegate items roles
	enum CC_PROPERTY_ROLE
	{
		OBJECT_NO_PROPERTY = 0,
		OBJECT_NAME,
		OBJECT_VISIBILITY,
		OBJECT_CURRENT_DISPLAY,
		OBJECT_NORMALS_SHOWN,
		OBJECT_COLOR_SOURCE,
		OBJECT_POLYLINE_WIDTH,
		OBJECT_SENSOR_DRAW_FRUSTUM,
		OBJECT_SENSOR_DRAW_FRUSTUM_PLANES,
		OBJECT_SF_SHOW_SCALE,
		OBJECT_OCTREE_LEVEL,
		OBJECT_OCTREE_TYPE,
		OBJECT_MESH_WIRE,
		OBJECT_MESH_STIPPLING,
		OBJECT_CURRENT_SCALAR_FIELD,
		OBJECT_CURRENT_COLOR_RAMP,
		OBJECT_IMAGE_ALPHA,
		OBJECT_APPLY_IMAGE_VIEWPORT,
		OBJECT_APPLY_SENSOR_VIEWPORT,
		OBJECT_CLOUD_SF_EDITOR,
		OBJECT_SENSOR_MATRIX_EDITOR,
		OBJECT_SENSOR_DISPLAY_SCALE,
		OBJECT_SENSOR_UNCERTAINTY,
		OBJECT_COLOR_RAMP_STEPS,
		OBJECT_MATERIALS,
		OBJECT_APPLY_LABEL_VIEWPORT,
		OBJECT_UPDATE_LABEL_VIEWPORT,
		OBJECT_LABEL_DISP_2D,
		OBJECT_LABEL_POINT_LEGEND,
		OBJECT_PRIMITIVE_PRECISION,
		OBJECT_CIRCLE_RESOLUTION,
		OBJECT_SPHERE_RADIUS,
		OBJECT_CIRCLE_RADIUS,
		OBJECT_CONE_HEIGHT,
		OBJECT_CONE_BOTTOM_RADIUS,
		OBJECT_CONE_TOP_RADIUS,
		OBJECT_CLOUD_POINT_SIZE,
		OBJECT_NAME_IN_3D,
		OBJECT_FACET_CONTOUR,
		OBJECT_FACET_MESH,
		OBJECT_PLANE_NORMAL_VECTOR,
		OBJECT_SENSOR_INDEX,
		OBJECT_SHOW_TRANS_BUFFER_PATH,
		OBJECT_SHOW_TRANS_BUFFER_TRIHDERONS,
		OBJECT_TRANS_BUFFER_TRIHDERONS_SCALE,
		OBJECT_HISTORY_MATRIX_EDITOR,
		OBJECT_GLTRANS_MATRIX_EDITOR,
		OBJECT_COORDINATE_SYSTEM_DISP_PLANES,
		OBJECT_COORDINATE_SYSTEM_DISP_AXES,
		OBJECT_COORDINATE_SYSTEM_AXES_WIDTH,
		OBJECT_COORDINATE_SYSTEM_DISP_SCALE,
		TREE_VIEW_HEADER,
		OBJECT_CLOUD_NORMAL_COLOR,
		OBJECT_CLOUD_NORMAL_LENGTH,
		OBJECT_CLOUD_DRAW_NORMALS,
		OBJECT_CLOUD_USE_LOD,
	};

	//! Default constructor
	ccPropertiesTreeDelegate(QStandardItemModel* _model, QAbstractItemView* _view, QObject* parent = nullptr);

	//! Default destructor
	~ccPropertiesTreeDelegate() override;

	// inherited from QStyledItemDelegate
	QSize    sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
	QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
	void     updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
	void     setEditorData(QWidget* editor, const QModelIndex& index) const override;

	void unbind();

	//! Fill property view with QItems corresponding to object's type
	void fillModel(ccHObject* hObject);

	//! Returns currently bound object
	ccHObject* getCurrentObject();

  Q_SIGNALS:
	void ccObjectPropertiesChanged(ccHObject* hObject) const;
	void ccObjectAppearanceChanged(ccHObject* hObject) const;
	void ccObjectAndChildrenAppearanceChanged(ccHObject* hObject) const;

  private:
	static const char* s_noneString;
	static const char* s_rgbColor;
	static const char* s_sfColor;
	static const char* s_defaultPointSizeString;
	static const char* s_defaultPolyWidthSizeString;

	void updateItem(QStandardItem*);
	void scalarFieldChanged(int);
	void colorScaleChanged(int);
	void colorRampStepsChanged(int);
	void spawnColorRampEditor();
	void octreeDisplayModeChanged(int);
	void octreeDisplayedLevelChanged(int);
	void primitivePrecisionChanged(int);
	void circleResolutionChanged(int);
	void sphereRadiusChanged(double);
	void circleRadiusChanged(double);
	void coneHeightChanged(double);
	void coneBottomRadiusChanged(double);
	void coneTopRadiusChanged(double);
	void imageAlphaChanged(int);
	void applyImageViewport();
	void applySensorViewport();
	void applyLabelViewport();
	void updateLabelViewport();
	void updateDisplay();
	void objectDisplayChanged(const QString&);
	void colorSourceChanged(const QString&);
	void sensorScaleChanged(double);
	void coordinateSystemDisplayScaleChanged(double);
	void sensorUncertaintyChanged();
	void sensorIndexChanged(double);
	void cloudPointSizeChanged(int);
	void polyineWidthChanged(int);
	void coordinateSystemAxisWidthChanged(int);
	void trihedronsScaleChanged(double);
	void normalColorChanged(int colorIdx);
	void normalLengthChanged(double length);

	void addSeparator(const QString& title);
	void appendRow(QStandardItem* leftItem, QStandardItem* rightItem, bool openPersistentEditor = false);
	void appendWideRow(QStandardItem* item, bool openPersistentEditor = true);

	void fillWithHObject(ccHObject*);
	void fillWithPointCloud(ccGenericPointCloud*);
	void fillWithDrawNormals(ccGenericPointCloud*);
	void fillWithPointCloudLOD(ccGenericPointCloud*);
	void fillSFWithPointCloud(ccGenericPointCloud*);
	void fillWithMesh(const ccGenericMesh*);
	void fillWithFacet(const ccFacet*);
	void fillWithPlanarEntity(const ccPlanarEntityInterface*);
	void fillWithSensor(const ccSensor*);
	void fillWithTransBuffer(const ccIndexedTransformationBuffer*);
	void fillWithPolyline(const ccPolyline*);
	void fillWithPrimitive(const ccGenericPrimitive*);
	void fillWithPointOctree(const ccOctree*);
	void fillWithPointKdTree(const ccKdTree*);
	void fillWithImage(const ccImage*);
	void fillWithLabel(const cc2DLabel*);
	void fillWithViewportObject(const cc2DViewportObject*);
	void fillWithGBLSensor(const ccGBLSensor*);
	void fillWithCameraSensor(const ccCameraSensor*);
	void fillWithMaterialSet(const ccMaterialSet*);
	void fillWithShareable(const CCShareable*);
	void fillWithMetaData(const ccObject*);
	void fillWithShifted(const ccShiftedObject*);
	void fillWithCoordinateSystem(const ccCoordinateSystem*);

	template <class Type, int N, class ComponentType>
	void fillWithCCArray(const ccArray<Type, N, ComponentType>*);

	//! Returns whether the editor is wide (i.e. spans on two columns) or not
	bool isWideEditor(int itemData) const;

	//! Updates the current model (assuming object is the same)
	void updateModel();

	ccHObject*          m_currentObject;
	QStandardItemModel* m_model;
	QAbstractItemView*  m_view;
	CC_PROPERTY_ROLE    m_lastFocusItemRole;
};

#endif
